﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace BullsEyeGame
{
    /// <summary>
    /// This form is the main form for this game where the whole board is set
    /// along with all the guesses and guess results
    /// </summary>
    public class FormGame : Form
    {
        private const int k_SizeOfGuessTargetButtonEdge = 40;
        private const int k_SizeOfGuessTargetButtonHorizontalPadding = 4;
        private const int k_SizeOfGuessTargetButtonVerticalPadding = 16;
        private const int k_SizeOfGuessButtonEdge = 40;
        private const int k_SizeOfGuessResultButtonEdge = 8;

        private const KnownColor k_MatchColor = KnownColor.Black;
        private const KnownColor k_MissColor = KnownColor.Yellow;
        private const bool k_Visible = true;
        private const bool k_Enabled = true;

        private FormRoundsSelector m_FormRoundsSelector;
        private List<Button> m_TargetGuess = new List<Button>();

        private List<GuessLine> m_GuessLines = new List<GuessLine>();
        private int m_SubmitedGuessCount = 0;

        public FormGame()
        {
            initializeComponent();
        }

        protected override void OnShown(EventArgs e)
        {
            DialogResult roundselectorDialogResult;

            base.OnShown(e);
            this.Visible = !k_Visible;
            m_FormRoundsSelector = new FormRoundsSelector();
            roundselectorDialogResult = m_FormRoundsSelector.ShowDialog();
            if (roundselectorDialogResult == DialogResult.OK)
            {
                initializeGameBoardAndStartNewGame();
            }
            else
            {
                this.Close();
            }
        }

        private void initializeComponent()
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.AutoSize = true;
            this.Text = "Bool Pgia";
            this.Visible = !k_Visible;
        }

        private void guessSubUnitButton_Click(object sender, EventArgs e)
        {
            Button buttonGuessSubUnitClicked = (Button)sender;
            FormColorBoard formColorBoard = new FormColorBoard();
            DialogResult dialogResult = formColorBoard.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                buttonGuessSubUnitClicked.BackColor = formColorBoard.LastChosenColor;
            }
        }

        private void submitGuessHandler(GuessLine i_GuessLine)
        {
            if (isLineSubmittedInCorrectOrder(i_GuessLine))
            {
                if (isValidGuessLine(i_GuessLine))
                {
                    actUponValidGuessSubmitted(i_GuessLine);               
                }
                else
                {
                    MessageBox.Show(this, "Sorry But You Will Have To Guess All Colors Before Submitting \nTry Again");
                }
            }
        }

        private bool isLineSubmittedInCorrectOrder(GuessLine i_GuessLineSubmitted)
        {
            return m_SubmitedGuessCount == i_GuessLineSubmitted.LineNumber;
        }

        private void actUponValidGuessSubmitted(GuessLine i_GuessLine)
        {
            const bool v_Won = true;
            GuessResult newGuessResult;

            i_GuessLine.SubmitGuessButtonEnabled = !k_Enabled;
            i_GuessLine.DisableGuessButtons();
            ++m_SubmitedGuessCount;

            newGuessResult = sendGuessAndGetResult(i_GuessLine);
            updateBoardAcordingToGuessResult(newGuessResult, i_GuessLine);
            if (newGuessResult.isMatch())
            {
                actUponGameEnded(v_Won);
            }
            else
            {
                if (isReachedMaxNumberOfGuesses())
                {
                    actUponGameEnded(!v_Won);
                }
            }
        }

        private void actUponGameEnded(bool i_GameWon)
        {
            string messageToUser;

            showTargetGuessColors();
            if (i_GameWon)
            {
                messageToUser = "Wow, You Cracked It!!!\nThank You For Playing....";
            }
            else
            {
                messageToUser = "Sorry But You Ran Out Of Guesses";
            }

            MessageBox.Show(this, messageToUser);
            this.Close();
        }

        private void showTargetGuessColors() 
        {
            List<KnownColor> targetGuessColors = getTargetGuessColors();
            setTargetGuessButtonsColor(targetGuessColors);
        }

        private List<KnownColor> getTargetGuessColors()
        {
            Guess targetGuess = GameLogics.Instance.TargetGuess;
            List<Guess.eGuessLetters> targateGuessLetters = targetGuess.GuessLetters;
            LettersColorsTranlator translator = LettersColorsTranlator.Instance;
            List<KnownColor> targetGuessColors = translator.TranslateLettersToColors(targateGuessLetters);
            return targetGuessColors;
        }

        private void setTargetGuessButtonsColor(List<KnownColor> targetGuessColors)
        {
            int currentTargetGuessButtonIndex = 0;

            foreach (KnownColor currentKnownColor in targetGuessColors)
            {
                m_TargetGuess[currentTargetGuessButtonIndex].BackColor = Color.FromKnownColor(currentKnownColor);
                currentTargetGuessButtonIndex++;
            }
        }

        private bool isReachedMaxNumberOfGuesses()
        {
            return m_SubmitedGuessCount == GameLogics.Instance.MaxNumberOfGuessesChosen;
        }

        private GuessResult sendGuessAndGetResult(GuessLine i_GuessLine)
        {            
            LettersColorsTranlator translator = LettersColorsTranlator.Instance;
            List<Color> guessSelectedColors;
            List<KnownColor> guessSelectedKnownColors;
            List<Guess.eGuessLetters> guessColorsInLetters;
            Guess newGuessToSubmit;
            guessSelectedColors = i_GuessLine.SelectedColors;
            guessSelectedKnownColors = translator.ColorsToKnowColors(guessSelectedColors);
            guessColorsInLetters = translator.TranslateColorsToLetters(guessSelectedKnownColors);
            newGuessToSubmit = Guess.CreateGuess(guessColorsInLetters);

            return GameLogics.Instance.AddNewGuess(newGuessToSubmit);
        }

        private void updateBoardAcordingToGuessResult(GuessResult i_GuessResult, GuessLine i_GuessLine)
        {
            int resultButtonIndex = 0;
            int numberOfMatch = i_GuessResult.NumberOfV;
            int numberOfMiss = i_GuessResult.NumberOfX;
            List<Button> guessResultButtons = i_GuessLine.GuessResultButtons;
            for (int i = 0; i < numberOfMatch; ++i)
            {
                guessResultButtons[resultButtonIndex].BackColor = Color.FromKnownColor(k_MatchColor);
                resultButtonIndex++;
            }

            for (int i = 0; i < numberOfMiss; ++i)
            {
                guessResultButtons[resultButtonIndex].BackColor = Color.FromKnownColor(k_MissColor);
                resultButtonIndex++;
            }
        }

        private bool isValidGuessLine(GuessLine i_GuessLine)
        {
            return i_GuessLine != null && i_GuessLine.IsValidGuessLine();
        }    
                
        private void initializeGameBoardAndStartNewGame()
        {
            int heightCenter, widthCenter;

            GameLogics.Instance.StartNewGame(m_FormRoundsSelector.NumberOfGuessesChosen);
            this.AutoSize = true;
            addTargetGuessLine();
            addGuessLines();
            widthCenter = SystemInformation.VirtualScreen.Width / 2;
            heightCenter = SystemInformation.VirtualScreen.Height / 2;
            this.Location = new Point(widthCenter - (this.Size.Width / 2), heightCenter - (this.Size.Height / 2));
            this.Visible = k_Visible;
        }

        private void addTargetGuessLine()
        {
            Button currentGuessTargetSubUnitButton;
            int left;

            for (int i = 0; i < Guess.GuessLength; ++i)
            {
                currentGuessTargetSubUnitButton = new Button();
                currentGuessTargetSubUnitButton.Size = new Size(k_SizeOfGuessTargetButtonEdge, k_SizeOfGuessTargetButtonEdge);
                currentGuessTargetSubUnitButton.BackColor = Color.Black;
                left = (i * (k_SizeOfGuessTargetButtonHorizontalPadding + k_SizeOfGuessTargetButtonEdge)) + k_SizeOfGuessTargetButtonHorizontalPadding;
                currentGuessTargetSubUnitButton.Location = new Point(left, k_SizeOfGuessTargetButtonVerticalPadding);
                currentGuessTargetSubUnitButton.Enabled = !k_Enabled;
                m_TargetGuess.Add(currentGuessTargetSubUnitButton);
                this.Controls.Add(currentGuessTargetSubUnitButton);
            }
        }

        private void addGuessLines()
        {
            GuessLine currentGuessLine;
            int numberOfGuessesChosen, linesVerticalStartingPoint;
            
            linesVerticalStartingPoint = k_SizeOfGuessTargetButtonEdge + (2 * k_SizeOfGuessTargetButtonVerticalPadding);
            numberOfGuessesChosen = m_FormRoundsSelector.NumberOfGuessesChosen;
            for (int i = 0; i < numberOfGuessesChosen; ++i)
            {
                currentGuessLine = new GuessLine(i, linesVerticalStartingPoint);
                currentGuessLine.SubmitDelegate += submitGuessHandler;
                addGuessLineToForm(currentGuessLine);
                m_GuessLines.Add(currentGuessLine);
            }
        }

        private void addGuessLineToForm(GuessLine i_GuessLine)
        {
            this.Controls.AddRange(i_GuessLine.Controls);
        }
    }
}